#!/usr/bin/env python
# coding=utf-8

if __name__ == '__main__':
    """ for file debug"""
    import sys,os
    sys.path.insert(0,os.path.join( os.getcwd(), '..' ))

__author__ = 'vavava'


import http.server
import threading,time
from queue import Queue
from vavava.workqueue import WorkQueue
from vavava.basethread import BaseThread

class MsgIn:
    def __init__(self,name,seq=-1,**param):
        self.seq=seq
        self.name=name
        self.param=param

class MsgOut:
    def __init__(self,name,seq=-1,param={}):
        self.seq=seq
        self.name=name
        self.param=param

class WSInfo:
    def __init__(self):
        self.name=""
        self.t=time.localtime(time.time())
        self.wqs=[]

class CmdProcessorBase:
    def __init__(self):
        self.typeId="base"
        self.name="<base-un-define>"

    def __lt__(self,o):
        return self.name > o.name

    def _do(self):
        pass

class WorkShop(BaseThread):

    def __init__(self,maxsize=20,minsize=10,ctrl_port=55555,log=None):
        BaseThread.__init__(self,"WorkShop",log)
        self.minsize=minsize
        self.maxsize=maxsize
        self.work_lines=[]
        self.msg_in=Queue(100)
        self.msg_out=Queue(100)
        self.cmd_processors={}
        for i in range(minsize):
            self.work_lines.append(WorkQueue(type=1,name="WQ_%d"%i))
        self.mt=threading.RLock()
        self.ctrl_port = ctrl_port
        self.http_ser = None
        if ctrl_port != 0:
            self.http_ser = CtrlServer(self,ctrl_port)

    def StartWork(self):
        try:
            self.http_ser.StartServer()
            self.log.debug("Start workshop")
            self._start_wqs()
            self.running_start()
            self.log.debug("Workshop started")
        except Exception as e:
            self.log.exception(e)

    def StopWork(self,timeout=30.0):
        self.log.debug("Stop workshop")
        self.running_stop()
        self._stop_wqs(timeout)
        self.join(timeout)
        self.log.debug("Workshop stopped")
        if self.http_ser:
            self.http_ser.StopServer()

    def RestartWork(self,timeout=30.0):
        self.StopWork(timeout)
        self.StartWork(timeout)

    def PauseWork(self,timeout=30.0):
        self.thread_pause()

    def ResumeWork(self,timeout=30.0):
        self.thread_resume()

    def AddTask(self,work):
        index = work.__hash__()%(self.minsize-1)
        self.work_lines[index].QueueWork(work)

    def AddCmdHandler(self,*handlers):
        self.mt.acquire()
        for handler in handlers:
            if issubclass(type(handler),CmdProcessorBase):
                self.cmd_processors[handler.name]=handler
        self.mt.release()

    def _start_wqs(self):
        for i in range(self.minsize):
            if not self.work_lines[i].IsAlive:
                self.work_lines[i].wq_start()

    def _stop_wqs(self,timeout=30.0):
        # not finished ???????
        self.log.debug("_stop_wqs")
        for i in range(len(self.work_lines)):
            line=self.work_lines[i]
            if line.IsAlive:
                line.wq_stop(timeout=0.5,flush=False)

    def run(self):
        self.log.debug("workshop routine begin")
        while self.IsRunning:
            try:
                self._cmd_handle()
                self._timeout_handle()
                time.sleep(0.5)
            except Exception as e:
                self.log.error("Workshop routine: exception")
                raise

        self.log.debug("workshop routine end")

    def _flush_out_msg(self):
        self.mt.acquire()
        self.msg_out = Queue(100)
        self.mt.release()

    def _cmd_handle(self):
        # process cmd
        if self.msg_in.not_empty == True: #?????
            msg = MsgIn("",None)
            msg = self.msg_in.get()
            cmd = msg.name.lower()
            self.log.debug("msg: "+cmd)
            v = self.cmd_processors.get(cmd)
            if cmd == "stop":
                self._stop_wqs()
                return False
            elif cmd == "pause":
                self.PauseWork()
            elif cmd == "pause":
                self.ResumeWork()
            elif cmd == "get info":
                wsi=WSInfo()
                wsi.name = "ws"
                for each in self.work_lines:
                    wsi.wqs.append(each.QueueInfo)
                response=MsgOut("info",None)
                response.param["info"] = wsi
                if self.msg_out.not_empty == True:
                    self._flush_out_msg()
                self.msg_out.put(response)
            elif v and cmd == v.name:
                ret= v._do(msg)
                if ret:
                    return ret
            else:
                self.log.warn("unknown cmd: "+cmd)
        return True

    def _timeout_handle(self):
        return True

    def send_request(self,cmd):
        return self.msg_in.put(cmd)

    def get_response(self):
        try:
            return self.msg_out.get(block=True,timeout=1.0)
        except Exception as e:
            return None

class CtrlServer(BaseThread):

    def __init__(self,ws,port=55555):
        BaseThread.__init__(self,"httpServer")
        self.ws = ws
        CtrlServer.WorkShopCtrl.ws=ws
        self.port = port
        self.httpd = http.server.HTTPServer( ("",port), CtrlServer.WorkShopCtrl)

    def StartServer(self):
        self.running_start()

    def StopServer(self,timeout=3):
        self.httpd.shutdown()
        self.running_stop()
        self.join(timeout)

    def run(self):
        while self.IsRunning:
            self.httpd.serve_forever()

    class WorkShopCtrl(http.server.BaseHTTPRequestHandler):
        ws=None
        def do_GET(self):
            if self.path == '/getinfo':      # 匹配 url ：/foo 的请求
                self.do_something()
            else:
                self.send_error(404) # 对于错误的请求，返回 404 错误

        def do_something(self):
            if self.ws:
                self.ws.send_request(MsgIn("get info"))
                mo = self.ws.get_response()
                if mo:
                    info=mo.param["info"].wqs
                    info_str = str(info)
                    self.send_response(200,info_str.encode("utf-8"))
                else:
                    self.send_error(500)
            else:
                self.send_error(500)

### test
class CmdProcessorCode(CmdProcessorBase):
    def __init__(self):
        CmdProcessorBase.__init__(self)
        self.name="code"

    def _do(self,cmd):
        s=cmd.param['code']
        exec(s)

def main():
    """
    http_ser = CtrlServer(None,55555)
    http_ser.running_start()
    http_ser.httpd.serve_forever()
"""
    cmd_code_handler = CmdProcessorCode()
    ws = WorkShop()
    ws.AddCmdHandler(cmd_code_handler)
    cmds=["get info","invalid_cmd","stop"]
    params=[
        MsgIn("get info"),
        MsgIn("invalid_cmd"),
        MsgIn(name="code",code="dir"),
        #MsgIn("restart"),
        MsgIn("stop")
    ]
    index=0
    size=len(cmds)
    count=1
    try:
        ws.StartWork()

        while True:
            time.sleep(2)

        while count>0:
            count -= 1
            if not ws.msg_out.empty():
                #mo=MsgOut()
                mo=ws.msg_out.get()
                info=mo.param["info"].wqs
                for i in info:
                    print (i)

            cmd = cmds[index] #input()
            index = (index+1)%size
            print(params[index].name)
            ws.send_reqest(params[index])
            time.sleep(2)
        ws.StopWork()
    except(KeyboardInterrupt):
        print('main thread(%f):stop'%time.clock())
        ws.StopWork()
        print('main thread(%f):stopped'%time.clock())



if __name__ == '__main__':
    main()
